#import "BpAliyunPushPlugin.h"
#import <Flutter/Flutter.h>
#import <CloudPushSDK/CloudPushSDK.h>
#import <UserNotifications/UserNotifications.h>

NSString *AliyunAppKey = @"";
NSString *AliyunAppSecret = @"";

const static NSString * __strong onReceiverNotification = @"onReceiverNotification";
const static NSString * __strong onReceiverMessage = @"onReceiverMessage";

@interface BpAliyunPushPlugin() <UNUserNotificationCenterDelegate>

@property (nonatomic, strong) FlutterMethodChannel *mChannel;

@end

@implementation BpAliyunPushPlugin {
    // iOS 10通知中心
    UNUserNotificationCenter *_notificationCenter;
    
    NSDictionary *_launchNotification;
}

+ (void)initKey:(NSString *)appkey appSecret:(NSString *)appSecret {
    AliyunAppKey = appkey;
    AliyunAppSecret = appSecret;
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
    
    FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"bp_aliyun_push"
                                                                binaryMessenger:[registrar messenger]];
    BpAliyunPushPlugin* instance = [[BpAliyunPushPlugin alloc] init];
    [registrar addApplicationDelegate:instance];
    [registrar addMethodCallDelegate:instance channel:channel];
    
    instance.mChannel = channel;
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
    if ([@"getPlatformVersion" isEqualToString:call.method]) {
        result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
    } else if([@"getLaunchNotification" isEqualToString:call.method]) {
        NSLog(@"BpAliyunPushPlugin getLaunchNotification");
        result(_launchNotification);
    } else if([@"bindAccount" isEqualToString:call.method]) {
        NSString *account = call.arguments;
        NSLog(@"BpAliyunPushPlugin bindAccount %@", account);
        [CloudPushSDK bindAccount:account withCallback:nil];
        result(nil);
    } else if([@"unbindAccount" isEqualToString:call.method]) {
        NSLog(@"BpAliyunPushPlugin unbindAccount");
        [CloudPushSDK unbindAccount:nil];
        result(nil);
    } else {
        result(FlutterMethodNotImplemented);
    }
}

#pragma mark - AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@"BpAliyunPushPlugin didFinishLaunchingWithOptions");
    
    [self initPush:application launchOptions:launchOptions];
    
    if (launchOptions != nil) {
        _launchNotification = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
    }
    
    if ([launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey]) {
        NSLog(@"BpAliyunPushPlugin launchOptions has Notification : %@", launchOptions);
        UILocalNotification *localNotification = [launchOptions valueForKey:UIApplicationLaunchOptionsLocalNotificationKey];
        NSMutableDictionary *localNotificationEvent = @{}.mutableCopy;
        localNotificationEvent[@"content"] = localNotification.alertBody;
        localNotificationEvent[@"badge"] = @(localNotification.applicationIconBadgeNumber);
        // 取得通知自定义字段内容，例：获取key为"Extras"的内容
        // NSString *extras = [userInfo valueForKey:@"extraMap"];
        localNotificationEvent[@"extras"] = localNotification.userInfo;
        localNotificationEvent[@"fireTime"] = [NSNumber numberWithLong:[localNotification.fireDate timeIntervalSince1970] * 1000];
        localNotificationEvent[@"soundName"] = [localNotification.soundName isEqualToString:UILocalNotificationDefaultSoundName] ? @"" : localNotification.soundName;
        
        if (@available(iOS 8.2, *)) {
            localNotificationEvent[@"title"] = localNotification.alertTitle;
        }
        _launchNotification = localNotificationEvent;
    }
    
    return YES;
}

#pragma mark - initPush

-(void)initPush:(UIApplication *)application launchOptions:(NSDictionary *)launchOptions  {
    // APNs注册，获取deviceToken并上报
    [self registerAPNS:application];
    // 初始化SDK
    [self initCloudPush:AliyunAppKey appSecret:AliyunAppSecret];
    // 监听推送通道打开动作
    [self listenerOnChannelOpened];
    // 监听推送消息到达
    [self registerMessageReceive];
    // 点击通知将App从关闭状态启动时，将通知打开回执上报
    [CloudPushSDK sendNotificationAck:launchOptions];
}

#pragma mark APNs Register

- (void)registerAPNS:(UIApplication *)application {
    if (@available(iOS 10.0,*)){
        _notificationCenter = [UNUserNotificationCenter currentNotificationCenter];
        _notificationCenter.delegate = self;
        // 请求推送权限
        [_notificationCenter requestAuthorizationWithOptions:UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {
            if (granted) {
                // granted
                NSLog(@"BpAliyunPushPlugin User authored notification.");
                // 向APNs注册，获取deviceToken
                dispatch_async(dispatch_get_main_queue(), ^{
                    [application registerForRemoteNotifications];
                });
            } else {
                // not granted
                NSLog(@"BpAliyunPushPlugin User denied notification.");
            }
        }];
    }
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"BpAliyunPushPlugin didRegisterForRemoteNotificationsWithDeviceToken");
    [CloudPushSDK registerDevice:deviceToken withCallback:^(CloudPushCallbackResult *res) {
        if (res.success) {
            NSLog(@"BpAliyunPushPlugin Register deviceToken success, deviceToken: %@", [CloudPushSDK getApnsDeviceToken]);
        } else {
            NSLog(@"BpAliyunPushPlugin Register deviceToken failed, error: %@", res.error);
        }
    }];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"BpAliyunPushPlugin didFailToRegisterForRemoteNotificationsWithError : %@", error);
}

#pragma mark - 主动获取设备通知是否授权(iOS 10+)

- (void)getNotificationSettingStatus {
    if (@available(iOS 10.0,*)){
        [_notificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
                NSLog(@"BpAliyunPushPlugin User authed.");
            } else {
                NSLog(@"BpAliyunPushPlugin User denied.");
            }
        }];
    }
}

#pragma mark SDK Init

- (void)initCloudPush:(NSString*)appkey appSecret:(NSString*)appSecret {
    // 正式上线建议关闭
    [CloudPushSDK turnOnDebug];
    // SDK初始化，手动输出appKey和appSecret
    [CloudPushSDK asyncInit:appkey appSecret:appSecret callback:^(CloudPushCallbackResult *res) {
        if (res.success) {
            NSLog(@"BpAliyunPushPlugin Push SDK init success, deviceId: %@.", [CloudPushSDK getDeviceId]);
        } else {
            NSLog(@"BpAliyunPushPlugin Push SDK init failed, error: %@", res.error);
        }
    }];
}

#pragma mark 注册推送通道打开监听

- (void)listenerOnChannelOpened {
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(onChannelOpened:)
                                                 name:@"CCPDidChannelConnectedSuccess"
                                               object:nil];
}

- (void)onChannelOpened:(NSNotification *)notification {
    NSLog(@"BpAliyunPushPlugin 消息通道建立成功");
}

#pragma mark 注册推送消息到来监听

- (void)registerMessageReceive {
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(onMessageReceived:)
                                                 name:@"CCPDidReceiveMessageNotification"
                                               object:nil];
}

- (void)onMessageReceived:(NSNotification *)notification {
    NSLog(@"BpAliyunPushPlugin onMessageReceived ------ Receive one message!");
    
    CCPSysMessage *message = [notification object];
    NSString *title = [[NSString alloc] initWithData:message.title encoding:NSUTF8StringEncoding];
    NSString *body = [[NSString alloc] initWithData:message.body encoding:NSUTF8StringEncoding];
    NSLog(@"BpAliyunPushPlugin Receive message title: %@, content: %@.", title, body);
    
    if(![NSThread isMainThread]) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self callFlutter:onReceiverMessage withDatas:body];
        });
    } else {
        [self callFlutter:onReceiverMessage withDatas:body];
    }
}

#pragma mark - UNUserNotificationCenterDelegate
/**
 *  App处于前台时收到通知(iOS 10+)
 */
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    NSLog(@"BpAliyunPushPlugin willPresentNotification ------ Receive a notification in foregound.");
    // 处理iOS 10通知，并上报通知打开回执
//    [self handleiOS10Notification:notification];
    // 通知不弹出
//    completionHandler(UNNotificationPresentationOptionNone);
    // 通知弹出，且带有声音、内容和角标
    completionHandler(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionList | UNNotificationPresentationOptionBanner);
}

/**
 *  触发通知动作时回调，比如点击、删除通知和点击自定义action(iOS 10+)
 */
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
    NSString *userAction = response.actionIdentifier;
    // 点击通知打开
    if ([userAction isEqualToString:UNNotificationDefaultActionIdentifier]) {
        NSLog(@"willPresentNotification didReceiveNotificationResponse ------ User opened the notification.");
        // 处理iOS 10通知，并上报通知打开回执
        [self handleiOS10Notification:response.notification];
    }
    // 通知dismiss，category创建时传入UNNotificationCategoryOptionCustomDismissAction才可以触发
    if ([userAction isEqualToString:UNNotificationDismissActionIdentifier]) {
        [CloudPushSDK sendDeleteNotificationAck:response.notification.request.content.userInfo];
    }
    
    completionHandler();
}

/**
 *  处理iOS 10通知(iOS 10+)
 */
- (void)handleiOS10Notification:(UNNotification *)notification {
    UNNotificationRequest *request = notification.request;
    UNNotificationContent *content = request.content;
    NSDictionary *userInfo = content.userInfo;
    // 通知时间
    NSDate *noticeDate = notification.date;
    // 标题
    NSString *title = content.title;
    // 副标题
    NSString *subtitle = content.subtitle;
    // 内容
    NSString *body = content.body;
    // 角标
    int badge = [content.badge intValue];
    // 取得通知自定义字段内容，例：获取key为"Extras"的内容
    NSString *extras = [userInfo valueForKey:@"Extras"];
    
    [self callFlutter:onReceiverNotification withDatas:userInfo];
    
    // 通知角标数清0
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    // 同步角标数到服务端
    // [self syncBadgeNum:0];
    // 通知打开回执上报
    [CloudPushSDK sendNotificationAck:userInfo];
    NSLog(@"Notification, date: %@, title: %@, subtitle: %@, body: %@, badge: %d, extras: %@.", noticeDate, title, subtitle, body, badge, extras);
}

/* 同步通知角标数到服务端 */
- (void)syncBadgeNum:(NSUInteger)badgeNum {
    [CloudPushSDK syncBadgeNum:badgeNum withCallback:^(CloudPushCallbackResult *res) {
        if (res.success) {
            NSLog(@"Sync badge num: %@ success.", @(badgeNum));
        } else {
            NSLog(@"Sync badge num: %@ failed, error: %@", @(badgeNum), res.error);
        }
    }];
}

#pragma mark - invokeMethod

- (void)callFlutter:(NSString *)eventName withDatas:(id _Nullable) datas {
    [self.mChannel invokeMethod:eventName arguments:datas];
}

@end
